﻿#include "MiVoice.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
//降噪与增益
#include "signal_processing_library.h"
#include "noise_suppression_x.h"
#include "noise_suppression.h"
#include "gain_control.h"
//vad
#include "webrtc_vad.h"
/**
* wangshuai
* pcm2wav.c
* head length =44
*/

#include <stdio.h>   
#include <string.h>  
#include <stdlib.h>	 

#pragma warning (disable :4996)
#define  uint32_t       unsigned int  
#define  uint16_t       unsigned short   

typedef struct _riff_t
{
	char riff[4];	/* "RIFF" (ASCII characters) */
	uint32_t len;	/* Length of package (binary, little endian) */
	char wave[4];	/* "WAVE" (ASCII characters) */
} riff_t;

/* The FORMAT chunk */

typedef struct _format_t {
	char  fmt[4];		/* "fmt_" (ASCII characters) */
	uint32_t   len;	/* length of FORMAT chunk (always 0x10) */
	uint16_t  type;		/* codec type*/
	uint16_t channel;	/* Channel numbers (0x01 = mono, 0x02 = stereo) */
	uint32_t   rate;	/* Sample rate (binary, in Hz) */
	uint32_t   bps;	/* Average Bytes Per Second */
	uint16_t blockalign;	/*number of bytes per sample */
	uint16_t bitpspl;	/* bits per sample */
} format_t;

typedef struct _data_t {
	char data[4];   /* "data" (ASCII characters) */
	uint32_t len;  /* length of data */
}data_t;

typedef struct _wav_head
{
	riff_t riff;
	format_t format;
	data_t   data;
}wav_head;

CMiVioce::~CMiVioce()
{
}
void CMiVioce::AgcTest(char *filename, char *outfilename, int mode)
{
	FILE *infp = NULL;
	FILE *outfp = NULL;
	short *pData = NULL;
	short *pOutData = NULL;
	void *agcHandle = NULL;
	do
	{
		WebRtcAgc_Create(&agcHandle);
		int minLevel = 0;
		int maxLevel = 255;
		int agcMode = mode;// kAgcModeFixedDigital;
		WebRtcAgc_Init(agcHandle, minLevel, maxLevel, agcMode, m_nSample);
		WebRtcAgc_config_t agcConfig;
		agcConfig.compressionGaindB = 20;
		agcConfig.limiterEnable = 1;
		agcConfig.targetLevelDbfs = 3;
		WebRtcAgc_set_config(agcHandle, agcConfig);
		infp = fopen(filename, "rb");
		int frameSize = m_nSample/100;
		pData = (short*)malloc(frameSize*sizeof(short));
		pOutData = (short*)malloc(frameSize*sizeof(short));
		outfp = fopen(outfilename, "wb");
		int len = frameSize*sizeof(short);
		int micLevelIn = 0;
		int micLevelOut = 0;
		while (TRUE)
		{
			memset(pData, 0, len);
			len = fread(pData, 1, len, infp);
			if (len > 0)
			{
				int inMicLevel = micLevelOut;
				int outMicLevel = 0;
				uint8_t saturationWarning;
				int nAgcRet = WebRtcAgc_Process(agcHandle, pData, NULL, frameSize, pOutData, NULL, inMicLevel, &outMicLevel, 0, &saturationWarning);
				if (nAgcRet != 0)
				{
					printf("failed in WebRtcAgc_Process\n");
					break;
				}
				micLevelIn = outMicLevel;
				fwrite(pOutData, 1, len, outfp);
			}
			else
			{
				break;
			}
		}
	} while (0);
	fclose(infp);
	fclose(outfp);
	free(pData);
	free(pOutData);
	WebRtcAgc_Free(agcHandle);
}
void CMiVioce::Ns16KSampleTest(char *szFileIn, char *szFileOut, int nSample, int nMode)//输入 输出 采样率 降噪级别1-4
{
	int nRet = 0;
	NsHandle *pNS_inst = NULL;

	FILE *fpIn = NULL;
	FILE *fpOut = NULL;

	char *pInBuffer = NULL;
	char *pOutBuffer = NULL;
	do
	{
	    int i = 0;
		int nFileSize = 0;
		int nTime = 0;
		if (0 != WebRtcNs_Create(&pNS_inst))
		{
			printf("Noise_Suppression WebRtcNs_Create err! \n");
			break;
		}
		if (0 != WebRtcNs_Init(pNS_inst, nSample))//根据采样率初始化降噪处理句柄
		{
			printf("Noise_Suppression WebRtcNs_Init err! \n");
			break;
		}
		if (0 != WebRtcNs_set_policy(pNS_inst, nMode))//nMode越高越好
		{
			printf("Noise_Suppression WebRtcNs_set_policy err! \n");
			break;
		}
		fpIn = fopen(szFileIn, "rb");
		if (NULL == fpIn)
		{
			printf("open src file err \n");
			break;
		}
		fseek(fpIn, 0, SEEK_END);
		nFileSize = ftell(fpIn);
		fseek(fpIn, 0, SEEK_SET);

		pInBuffer = (char*)malloc(nFileSize);
		memset(pInBuffer, 0, nFileSize);
		fread(pInBuffer, sizeof(char), nFileSize, fpIn);

		pOutBuffer = (char*)malloc(nFileSize);
		memset(pOutBuffer, 0, nFileSize);

		int  filter_state1[6], filter_state12[6];
		int  Synthesis_state1[6], Synthesis_state12[6];

		memset(filter_state1, 0, sizeof(filter_state1));
		memset(filter_state12, 0, sizeof(filter_state12));
		memset(Synthesis_state1, 0, sizeof(Synthesis_state1));
		memset(Synthesis_state12, 0, sizeof(Synthesis_state12));

		nTime = GetTickCount();
		if (m_nSample == 32000)
		{
			for (i = 0; i < nFileSize; i += (int)(sizeof(short)*m_nSample / 100))
			{
				if (nFileSize - i >=(int)( m_nSample / 100 * 2))
				{
					short shBufferIn[320] = { 0 };
					short shInL[160], shInH[160];
					short shOutL[160] = { 0 }, shOutH[160] = { 0 };
					memcpy(shBufferIn, (char*)(pInBuffer + i), 320 * sizeof(short));
					//首先需要使用滤波函数将音频数据分高低频，以高频和低频的方式传入降噪函数内部
					WebRtcSpl_AnalysisQMF(shBufferIn, 320, shInL, shInH, filter_state1, filter_state12);
					//将需要降噪的数据以高频和低频传入对应接口，同时需要注意返回数据也是分高频和低频
					if (0 == WebRtcNs_Process(pNS_inst, shInL, shInH, shOutL, shOutH))
					{
						short shBufferOut[320];
						//如果降噪成功，则根据降噪后高频和低频数据传入滤波接口，然后用将返回的数据写入文件
						WebRtcSpl_SynthesisQMF(shOutL, shOutH, 160, shBufferOut, Synthesis_state1, Synthesis_state12);
						memcpy(pOutBuffer + i, shBufferOut, 320 * sizeof(short));
					}
				}
			}
		}
		if (m_nSample == 16000)
		{
			for (i = 0; i < nFileSize; i += sizeof(short)*m_nSample /100)
			{
				if (nFileSize - i >=320)
				{
					short shBufferIn[160] = { 0 };
					short shBufferOut[160] = { 0 };
					memcpy(shBufferIn, (char*)(pInBuffer + i), 160 * sizeof(short));
					if (0 == WebRtcNs_Process(pNS_inst, shBufferIn, NULL, shBufferOut, NULL))
					{
						printf("error");
					}
					memcpy(pOutBuffer + i, shBufferOut, 160 * sizeof(short));

				}
			}
		}
		nTime = GetTickCount() - nTime;
		printf("用了%dms\n", nTime);
		fpOut = fopen(szFileOut, "wb");
		if (NULL == fpOut)
		{
			printf("open out file err! \n");
			break;
		}
		fwrite(pOutBuffer, sizeof(char), nFileSize, fpOut);
	} while (0);

	WebRtcNs_Free(pNS_inst);
	fclose(fpIn);
	fclose(fpOut);
	free(pInBuffer);
	free(pOutBuffer);

}
void CMiVioce::NSx16KSampleTest(char *szFileIn, char *szFileOut, int nSample, int nMode)
{
	int nRet = 0;
	NsxHandle *pNS_inst = NULL;
	FILE *fpIn = NULL;
	FILE *fpOut = NULL;
	char *pInBuffer = NULL;
	char *pOutBuffer = NULL;
	do
	{
		int i = 0;
		int nFileSize = 0;
		int nTime = 0;
		if (0 != WebRtcNsx_Create(&pNS_inst))//创建降噪句柄
		{
			printf("Noise_Suppression WebRtcNs_Create err! \n");
			break;
		}
		if (0 != WebRtcNsx_Init(pNS_inst, nSample))//初始化降噪句柄 设置采样率
		{
			printf("Noise_Suppression WebRtcNs_Init err! \n");
			break;
		}
		if (0 != WebRtcNsx_set_policy(pNS_inst, nMode))//设置降噪策略 降噪级别0，1，2，3
		{
			printf("Noise_Suppression WebRtcNs_set_policy err! \n");
			break;
		}
		fpIn = fopen(szFileIn, "rb");
		if (NULL == fpIn)
		{
			printf("open src file err \n");
			break;
		}
		fseek(fpIn, 0, SEEK_END);
		nFileSize = ftell(fpIn);
		fseek(fpIn, 0, SEEK_SET);
		pInBuffer = (char*)malloc(nFileSize);
		memset(pInBuffer, 0, nFileSize);
		fread(pInBuffer, sizeof(char), nFileSize, fpIn);
		pOutBuffer = (char*)malloc(nFileSize);
		memset(pOutBuffer, 0, nFileSize);
		int  filter_state1[6], filter_state12[6];
		int  Synthesis_state1[6], Synthesis_state12[6];
		memset(filter_state1, 0, sizeof(filter_state1));
		memset(filter_state12, 0, sizeof(filter_state12));
		memset(Synthesis_state1, 0, sizeof(Synthesis_state1));
		memset(Synthesis_state12, 0, sizeof(Synthesis_state12));
		nTime = GetTickCount();
		if (m_nSample == 32000)
		{
			for (i = 0; i < nFileSize; i += 640)
			{
			if (nFileSize - i >= 640)
			{
				short shBufferIn[320] = { 0 };
				short shInL[160], shInH[160];
				short shOutL[160] = { 0 }, shOutH[160] = { 0 };
				memcpy(shBufferIn, (char*)(pInBuffer + i), 320 * sizeof(short));
				//首先需要使用滤波函数将音频数据分高低频，以高频和低频的方式传入降噪函数内部
				WebRtcSpl_AnalysisQMF(shBufferIn, 320, shInL, shInH, filter_state1, filter_state12);

				//将需要降噪的数据以高频和低频传入对应接口，同时需要注意返回数据也是分高频和低频
				if (0 == WebRtcNsx_Process(pNS_inst, shInL, shInH, shOutL, shOutH))
				{
					short shBufferOut[320];
					//如果降噪成功，则根据降噪后高频和低频数据传入滤波接口，然后用将返回的数据写入文件
					WebRtcSpl_SynthesisQMF(shOutL, shOutH, 160, shBufferOut, Synthesis_state1, Synthesis_state12);
					memcpy(pOutBuffer + i, shBufferOut, 320 * sizeof(short));
				}
			}
		}
		}
		if (m_nSample == 16000)
		{
			if (m_nSample == 16000)
			{
				for (i = 0; i < nFileSize; i += sizeof(short)*m_nSample / 100)
				{
					if (nFileSize - i >= 320)
					{
						short shBufferIn[160] = { 0 };
						short shBufferOut[160] = { 0 };
						memcpy(shBufferIn, (char*)(pInBuffer + i), 160 * sizeof(short));
						if (0 == WebRtcNsx_Process(pNS_inst, shBufferIn, NULL, shBufferOut, NULL))
						{
							printf("error");
						}
						memcpy(pOutBuffer + i, shBufferOut, 160 * sizeof(short));

					}
				}
			}
		}
		nTime = GetTickCount() - nTime;
		printf("n_s user time=%dms\n", nTime);
		fpOut = fopen(szFileOut, "wb");
		if (NULL == fpOut)
		{
			printf("open out file err! \n");
			break;
		}
		fwrite(pOutBuffer, sizeof(char), nFileSize, fpOut);
	} while (0);

	WebRtcNsx_Free(pNS_inst);
	fclose(fpIn);
	fclose(fpOut);
	free(pInBuffer);
	free(pOutBuffer);

}
void CMiVioce::VadTest(char*pAudioFile, char *pResFile, int nSample, int nMode)
{

	VadInst* pVad = NULL;
	if (WebRtcVad_Create(&pVad))
	{
		perror("WebRtcVad_Create failed!");
		return;
	}

	if (WebRtcVad_Init(pVad))
	{
		perror("WebRtcVad_Init failed!");
		return;
	}

	if (WebRtcVad_set_mode(pVad, nMode))
	{
		perror("WebRtcVad_set_mode failed!");
		return;
	}
	FILE* fp = NULL;
	FILE* fpR = NULL;

	FILE* pFilrArr[256];//1,定义文件指针数组
	fp = fopen(pAudioFile, "rb");
	fpR = fopen(pResFile, "wb");
	fseek(fp, 0, SEEK_END);
	unsigned int nLen = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	short shBufferIn[320] = { 0 };

	int nlast = 1001;
	int sum = 0;
	pFilrArr[0] = fopen("0.wav", "wb");
	while (1)
	{
		if (320 != fread(shBufferIn, 2, 320, fp))//160个short
			break;
		int nRet = WebRtcVad_Process(pVad, 32000, shBufferIn, 320);
		printf("%d", nRet);
		if (nlast == 0 && nRet ==1)
		{
			sum++;
			char cFile[256]=""; 
			itoa(sum, cFile, 10);
			char* wav = ".pcm";
			strcat(cFile, wav);
			pFilrArr[sum] = fopen(cFile,"wb");
		}
		if (1 == nRet)
		{
			fwrite(shBufferIn, 2, 320, fpR);
			fwrite(shBufferIn, 2, 320, pFilrArr[sum]);
		}
		
		nlast = (nRet == 1) ? 1 : 0;
	}
	for (int n = 0; n <= sum;n++)
	{
		fclose(pFilrArr[n]);
	}
	for (int n = 1; n <= sum;n++)
	{
		char cFile[256] = "";
		itoa(n, cFile, 10);
		char* wav = ".pcm";
		strcat(cFile, wav);

		char cFile1[256] = "";
		itoa(n, cFile1, 10);
		char* wav1 = ".wav";
		strcat(cFile1, wav1);

		PcmToWav(cFile, cFile1, 16);
	}
	fclose(fpR);
	fclose(fp);
	WebRtcVad_Free(pVad);
}
 //void CMiVioce::VadTest(char*pAudioFile, char *pResFile, int nSample, int nMode)const
 //{
 //	
 //	VadInst* pVad = NULL;
 //	if (WebRtcVad_Create(&pVad))
 //	{
 //		perror("WebRtcVad_Create failed!");
 //		return;
 //	}
 //
 //	if (WebRtcVad_Init(pVad))
 //	{
 //		perror("WebRtcVad_Init failed!");
 //		return;
 //	}
 //
 //	if (WebRtcVad_set_mode(pVad, nMode))
 //	{
 //		perror("WebRtcVad_set_mode failed!");
 //		return;
 //	}
 //	FILE* fp = NULL;
 //	FILE* fpR = NULL;
 //	fp = fopen(pAudioFile, "rb");
 //	fpR = fopen(pResFile, "wb");
 //	fseek(fp, 0, SEEK_END);
 //	unsigned int nLen = ftell(fp);
 //	fseek(fp, 0, SEEK_SET);
 //	short shBufferIn[320] = { 0 };
 //	while (1)
 //	{
 //		if (320 != fread(shBufferIn, 2, 320, fp))//160个short
 //			break;
 //		int nRet = WebRtcVad_Process(pVad, 32000, shBufferIn, 320);
	//	printf("%d", nRet);
 //		if (1 == nRet)
 //		{
 //			fwrite(shBufferIn, 2, 320, fpR);
 //		}
 //		if (0 == nRet)
 //		{
 //
 //		}
 //	}
 //	fclose(fpR);
 //	fclose(fp);
 //	WebRtcVad_Free(pVad);
 //}

void CMiVioce::MiWebVad(char*putfilename, char*outFilename)const
{
	FILE *fpInputf, *fpOutput;
	fpInputf = fopen(putfilename, "rb");
	if (fpInputf == NULL){
		return;
	}
	fpOutput = fopen(outFilename, "wb");
	VadInst*inst = NULL;
	WebRtcVad_Create(&inst);
	WebRtcVad_Init(inst);
	WebRtcVad_set_mode(inst, 2);
	const unsigned int  FRAMELENGTH = 160;
	short audioFrame[FRAMELENGTH];
	
	while (!feof(fpInputf))
	{
		int read_size = fread(audioFrame, sizeof(short), m_nSample/100, fpInputf);
		int status = WebRtcVad_Process(inst, m_nSample, audioFrame, m_nSample/100);
		if (status == -1)
		{
			printf("WebRtcVad_Process is error\n");
			return;
		}
		printf("%d", status);
		if (status == 1){
			fwrite(audioFrame, sizeof(short), read_size, fpOutput);
			fflush(fpOutput);
		}
	}
	fclose(fpOutput);
	fclose(fpInputf);
	WebRtcVad_Free(inst);
}

void CMiVioce::PcmToWav(char*src_file, char* dst_file, int bits)
{
	wav_head header;
	FILE   *fp, *fpCpy;
	printf("parameter analyse succeess\n");
	if ((fp = fopen(src_file, "rb")) == NULL) //读取文件    
	{
		printf("open pcm file  error\n");
		return;
	}
	if ((fpCpy = fopen(dst_file, "wb")) == NULL) //为转换建立一个新文件    
	{
		printf("create wav file error\n");
		return;
	}
	//以下是创建wav头的HEADER;但.dwsize未定，因为不知道Data的长度。    
	memcpy(header.riff.riff, "RIFF", 4);
	memcpy(header.riff.wave, "WAVE", 4);
	//以上是创建wav头的HEADER;    
	if (ferror(fpCpy))
	{
		printf("error\n");
	}
	memcpy(&header.format.fmt, "fmt ", 4);
	header.format.len = 0x10;
	header.format.type = 0x1;
	header.format.channel = m_nChannel;
	header.format.rate = m_nSample;
	header.format.bps = m_nSample * bits / 8 * m_nChannel;
	header.format.blockalign = bits / 8 * m_nChannel;
	header.format.bitpspl = bits;
	memcpy(&header.data.data, "data", 4);
	fseek(fp, 0, SEEK_END);
	long count = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	printf("length:%ud", count);
	header.data.len = (uint32_t)count;
	header.riff.len = header.data.len + 36;
	int size = sizeof(header);
	//fwrite(&header, 1, sizeof(header), fpCpy);
	fwrite(&header, sizeof(header), 1, fpCpy);
	char *buffer = (char *)malloc((count)* sizeof(char));
	fread(buffer, 1, count, fp);
	//fwrite(buffer, 1, count, fpCpy);
	fwrite(buffer, 1, count, fpCpy);
	free(buffer);
	fclose(fp); //关闭文件    
	fclose(fpCpy);   //关闭文件   
}
void CMiVioce::WavToPcm(char* src_file, char*dst_file)
{
	
	uint32_t pcm_data_size = 0;
	int pcm_channel = m_nChannel;
	int pcm_samplerate = m_nSample;
	//以下是为了建立.wav头而准备的变量    
	wav_head header;
	FILE   *fp = NULL, *fpCpy = NULL;
	int flen;
	if ((fp = fopen(src_file, "rb")) == NULL) //读取文件    
	{
		printf("open pcm file  error\n");
		return;
	}
	//直接去掉44个字节,但是感觉这种方法不好
	//if ((flen=fread(&header,1,44,fp))!=44) 
	//{
	//	goto error;
	//}

	if ((flen = fread(&header.riff.riff, 1, 4, fp)) != 4)
		goto error;

	if (memcmp(&header.riff.riff, "RIFF", 4))
		goto error;

	if ((flen = fread(&header.riff.len, 1, 4, fp)) != 4)
		goto error;

	if ((flen = fread(&header.riff.wave, 1, 4, fp)) != 4)
		goto error;

	if (memcmp(&header.riff.wave, "WAVE", 4))
		goto error;

	if ((flen = fread(&header.format.fmt, 1, 4, fp)) != 4)
		goto error;

	if (memcmp(&header.format.fmt, "fmt ", 4))
		goto error;

	if ((flen = fread(&header.format.len, 1, 4, fp)) != 4)
	{
		goto error;
	}
	if (header.format.len != 0x10)
	{
		printf("header.format.len!=0x10 :value:%d\n", header.format.len);
	}
	if ((flen = fread(&header.format.type, 1, 2, fp)) != 2)
	{
		goto error;
	}
	if (header.format.type != 0x1)
	{
		printf("header.format.type != 0x1 :value:%d\n", header.format.type);
	}
	if ((flen = fread(&header.format.channel, 1, 2, fp)) != 2)
	{
		goto error;
	}
	pcm_channel = header.format.channel;//通道数的数据

	if ((flen = fread(&header.format.rate, 1, 4, fp)) != 4)
	{
		goto error;
	}
	pcm_samplerate = header.format.rate;

	if ((flen = fread(&header.format.bps, 1, 4, fp)) != 4)
	{
		goto error;
	}

	if ((flen = fread(&header.format.blockalign, 1, 2, fp)) != 2)
	{
		goto error;
	}

	if ((flen = fread(&header.format.bitpspl, 1, 2, fp)) != 2)
	{
		goto error;
	}

	int p = 0;
	//后面的结构可能不是直接为“data”
	do {
		if ((flen = fread(&header.data.data, 1, 4, fp)) != 4)
		{
			goto error;
		}
		if (memcmp(&header.data.data, "data", 4) == 0)
		{
			printf("find data chunk.");
			if ((flen = fread(&header.data.len, 1, 4, fp)) != 4)
			{
				goto error;
			}
			pcm_data_size = header.data.len;
			break;
		}
		else
			p += 4;

	} while (!feof(fp));

	printf("解析成功，二个PCM数据长度分别为:%d, %d\n", pcm_data_size, header.riff.len - 36);

	int otherdataSize = header.riff.len - 36 - pcm_data_size;
	if (otherdataSize > 0)
	{
		printf("多余的数据部分大小：%d , %d", p, otherdataSize);
		char *otherdata = (char *)malloc(otherdataSize + 1);
		memset(otherdata, 0, otherdataSize + 1);
		fseek(fp, -otherdataSize - 8, SEEK_CUR);
		fread(otherdata, 1, otherdataSize, fp);
		*(otherdata + otherdataSize) = '\0';
		fseek(fp, 8, SEEK_CUR);
		printf("other data:%s", otherdata);
	}
	fseek(fp, otherdataSize + 44, SEEK_SET);

	//fseek(fp, 0, SEEK_CUR);

	unsigned char *buffer = (unsigned char*)malloc((pcm_data_size)* sizeof(char));

	memset(buffer, 0, pcm_data_size);

	int count1 = fread(buffer, 1, pcm_data_size, fp);

	char output[1024] = { 0 };
	//sprintf(output, "%d_%d_.pcm", pcm_samplerate, pcm_channel);
	sprintf(output, dst_file);

	if ((fpCpy = fopen(output, "wb+")))
	{
		//fwrite(buffer, 1, sizeof(buffer), fpCpy);  写了段常犯错的代码
		fwrite(buffer, 1, pcm_data_size, fpCpy);
	}
	else
		goto error;

	free(buffer);
	fclose(fp); //关闭文件    
	fclose(fpCpy);   //关闭文件    

	return;

error:
	if (fp)
	{
		fclose(fp);
	}
	if (fpCpy)
	{
		fclose(fpCpy);
	}
	return;
}
